Skip to content

fix: harden Therapy Compass recovery and error accessibility#800

Closed
BigSimmo wants to merge 5 commits into
mainfrom
cursor/therapy-compass-recovery-db17
Closed

fix: harden Therapy Compass recovery and error accessibility#800
BigSimmo wants to merge 5 commits into
mainfrom
cursor/therapy-compass-recovery-db17

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Verification

  • Hosted Static PR checks / Build / Unit coverage / Advisory UI on predecessor heads.
  • npm run verify:ui evidence via hosted UI gates on predecessor heads.
  • UI verification not run locally in this babysit pass: relying on hosted Production UI.

Risk and rollout

  • Risk: medium; recovery and error-boundary UX for Therapy Compass and global/route errors.
  • Rollback: revert this PR; prior error/empty rendering returns.
  • Provider or production effects: None

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed
Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Added a Retry option when Therapy Compass data fails to load.
    • Improved keyboard focus handling after application and route errors.
    • Updated error screens to adapt to system themes and color settings.
  • Bug Fixes

    • Prevented stale requests from incorrectly clearing newer data.
    • Disabled the unavailable favourites control and clarified its status.

cursoragent and others added 4 commits July 17, 2026 20:31
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Keep Retry focus during reload, guard the shared dataset cache against
stale rejection handlers, and restore visible focus on error headings.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@supabase

supabase Bot commented Jul 17, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Error boundaries now move focus to their headings and use system color tokens. Therapy Compass adds retryable dataset loading, an error fallback with retry controls, and disables the unavailable favourites action.

Changes

Accessibility and Therapy Compass recovery

Layer / File(s) Summary
Error boundary focus and styling
src/app/global-error.tsx, src/components/route-error-boundary.tsx
Error headings receive focus after capture, and global error UI colors use system theme tokens.
Therapy data retry contract and provider wiring
src/components/therapy-compass/data/use-therapy-data.ts, src/components/therapy-compass/bindings.tsx
Dataset loading can be retried through cache invalidation and attempt tracking, with retryData exposed through provider bindings.
Therapy Compass error and unavailable actions
src/components/therapy-compass/therapy-compass-page.tsx, src/components/therapy-compass/therapy-card.tsx
The page renders retry-aware error UI, while the favourites button is disabled and marked unavailable.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TherapyCompassPage
  participant TcProvider
  participant useTherapyData
  participant SharedDatasetCache
  TherapyCompassPage->>TcProvider: invoke retryData
  TcProvider->>useTherapyData: invoke retry
  useTherapyData->>SharedDatasetCache: clear cache and start retry request
  SharedDatasetCache-->>useTherapyData: return data or error
  useTherapyData-->>TcProvider: update loading and error state
  TcProvider-->>TherapyCompassPage: render retry state
Loading

Possibly related PRs

  • BigSimmo/Database#650: Introduces the Therapy Compass data-loading and provider flow extended here with retry handling.
  • BigSimmo/Database#758: Directly overlaps the error accessibility, retry wiring, and disabled favourites changes.
  • BigSimmo/Database#798: Touches the same error-boundary and Therapy Compass retry code paths.

Suggested reviewers: claude

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: hardening Therapy Compass recovery and error accessibility.
Description check ✅ Passed The description covers summary, verification, risk/rollback, and clinical governance sections with mostly complete content.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/therapy-compass-recovery-db17

Comment @coderabbitai help to get the list of available commands.

@cursor
cursor Bot enabled auto-merge (squash) July 17, 2026 20:58
@cursor
cursor Bot force-pushed the cursor/therapy-compass-recovery-db17 branch from 31697fc to ec42c40 Compare July 17, 2026 20:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/route-error-boundary.tsx`:
- Line 62: Update the error heading’s focus styling in the route error boundary
to use focus-triggered utilities instead of focus-visible, ensuring the recovery
focus applied by useEffect always shows the outline. Preserve the existing
outline width, offset, and focus-ring color values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 615b8417-e4ab-42ed-b04f-1c635639cc0c

📥 Commits

Reviewing files that changed from the base of the PR and between 3ff8095 and 89c9f09.

📒 Files selected for processing (6)
  • src/app/global-error.tsx
  • src/components/route-error-boundary.tsx
  • src/components/therapy-compass/bindings.tsx
  • src/components/therapy-compass/data/use-therapy-data.ts
  • src/components/therapy-compass/therapy-card.tsx
  • src/components/therapy-compass/therapy-compass-page.tsx

<h1
ref={headingRef}
tabIndex={-1}
className="mt-4 text-lg font-semibold tracking-tight text-[color:var(--text-heading)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus-ring,Highlight)]"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the component structure first, then read the relevant slice.
ast-grep outline src/components/route-error-boundary.tsx --view expanded || true
printf '\n--- file slice ---\n'
sed -n '1,180p' src/components/route-error-boundary.tsx | cat -n

Repository: BigSimmo/Database

Length of output: 4976


🌐 Web query:

CSS :focus-visible script focus after pointer interaction heuristics MDN

💡 Result:

The:focus-visible pseudo-class applies to an element when it is focused and the browser's User Agent (UA) determines, through internal heuristics, that a visible focus indicator is necessary [1]. This allows developers to display focus styles only when they would be most helpful—primarily for keyboard users—while avoiding potentially distracting focus rings during pointer interactions [1][2][3]. Heuristics for:focus-visible The specific heuristics used by browsers are not defined normatively in the CSS specification, which grants UAs flexibility in implementation [4][5][6]. However, modern browser engines have converged on a common set of behaviors [2]: 1. Keyboard Interaction: If an element receives focus via a keyboard interaction (e.g., Tab key),:focus-visible will almost always match, as the user is clearly navigating by keyboard [1][2][3]. 2. Pointer Interaction: Generally, when an element is focused via a mouse click, touch, or other pointing device,:focus-visible does not match [1][3]. This prevents focus styles from "sticking" on elements like buttons after they are clicked, which can be confusing for users [7]. 3. Input Elements: Elements that require user input, such as text fields (e.g., or <textarea>), typically match:focus-visible regardless of how focus was received [1][2]. This is because it is essential for the user to know where their typed input will be placed [1][2]. Regarding the:focus-visible polyfill (WICG/focus-visible): Before widespread native support, a polyfill script was commonly used to achieve this behavior [8]. This script used its own set of heuristics to mimic native support [8][5]: - Keyboard Modality: It tracked whether the last interaction was a keyboard event (like Tab) and added a.focus-visible class accordingly [4][8]. - Focus Events: It would trigger focus visibility if an element that required keyboard interaction (like a text field) received focus [8]. - Limitations: Because the polyfill had to rely on events available to JavaScript, it could not perfectly replicate the internal, low-level browser heuristics, leading to slight variations in behavior compared to modern native implementations [8][5]. Today, developers are encouraged to use the native:focus-visible pseudo-class directly, as it is supported by all major browsers and integrates natively with the browser's own focus-tracking logic [1][2][8]. Top Results: [1][2][5][3]

Citations:


🌐 Web query:

MDN :focus-visible keyboard modality pointer programmatic focus

💡 Result:

The:focus-visible pseudo-class is a CSS selector that matches an element only when the User Agent determines, via internal heuristics, that a focus indicator is necessary [1]. Its primary purpose is to distinguish between situations where a focus indicator is helpful (e.g., keyboard navigation) and where it might be considered obtrusive (e.g., clicking a button with a mouse) [1][2]. Regarding programmatic focus and modality: 1. Modality and Heuristics: Browsers use heuristics to determine the input modality [2]. Generally, if the user interacts via the keyboard,:focus-visible matches the focused element [1]. If the user interacts via a pointing device, it typically does not match on elements that do not require text input (like buttons) [1]. 2. Programmatic Focus (element.focus): When focus is moved programmatically, the behavior of:focus-visible depends on the context [3][4]. - Initial focus (e.g., page load or autofocus): Browsers typically trigger:focus-visible by default because there is no prior "modality" context [4]. - Focus transfer: If an element currently matches:focus-visible (e.g., the user is already navigating via keyboard), moving focus programmatically to a new element will often cause the new element to also match:focus-visible [3][4]. Conversely, if the element does not match, the new element typically will not [3][4]. 3. Forcing Visibility: Because browser heuristics for programmatic focus can sometimes lead to inconsistent results for developers, the focus method has been extended in many modern environments to accept an options object that includes a focusVisible property [5][6]. Example: element.focus({ focusVisible: true }); Setting focusVisible: true explicitly instructs the browser to show the focus indicator and ensures:focus-visible matches, regardless of the current inferred input modality [5][6].

Citations:


Use a focus style that always appears on the error heading.

Because this heading is focused in useEffect, focus-visible: can be skipped after pointer-driven failures. Switch these utilities to focus: or apply an explicit focused state so recovery focus is always visible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/route-error-boundary.tsx` at line 62, Update the error
heading’s focus styling in the route error boundary to use focus-triggered
utilities instead of focus-visible, ensuring the recovery focus applied by
useEffect always shows the outline. Preserve the existing outline width, offset,
and focus-ring color values.

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Superseded: Therapy Compass recovery already landed via #798; residual role="alert" landed in #808 (now merged). Please close this PR.

@BigSimmo BigSimmo closed this Jul 18, 2026
auto-merge was automatically disabled July 18, 2026 06:22

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants